home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / pascal / qpf.com / QPF.PAS < prev   
Encoding:
Pascal/Delphi Source File  |  1990-10-28  |  15.6 KB  |  683 lines

  1. PROGRAM QPF;
  2. {$A-}    {Disable Word Alignment}
  3. {$B-}    {Short Circuit Boolean}
  4. {$D-}    {Disable DEBUG Info}
  5. {$R-}    {Disable Range Checking}
  6. {$S-}    {Disable Stack Checking}
  7. {$V-}    {Disable VAR String Checking}
  8. {$I-}    {Disable I/O Checking}
  9.  
  10. { --------------------------------------------------------
  11. Purpose : Fixup PASCAL words into a standard format.
  12. Author    : Greg Tesch
  13. History    : 12/14/89    Initial Version
  14. ---------------------------------------------------------- }
  15.  
  16. USES Dos;
  17.  
  18. CONST
  19.     IdentSet : SET OF Char = ['A'..'Z', 'a'..'z', '_'];
  20.     DelimSet : SET OF Char = ['('..'/',':'..'>','@','[',']','^','{','}'];
  21.     LiteralSet : SET OF Char = [#39,'$','#'];
  22.     DigitSet : SET OF Char = ['0'..'9'];
  23.     HexSet : SET OF Char = ['0'..'9','A'..'F','a'..'f'];
  24.     Quote = '''';
  25.  
  26. TYPE
  27.     StmtPtr = ^StmtRec;
  28.     StmtRec = RECORD
  29.         Next : StmtPtr;
  30.         Stmt : STRING;
  31.     END;
  32.     Tokens = (Identifier, Literal, Other);
  33.     SmallStr = STRING[15];                { Small String For Arrays }
  34.  
  35. VAR
  36.     InFileName,OutFileName : DirStr;    { Input/Output File names }
  37.     Token : STRING;                        { Global Token Variable }
  38.     TokenType : Tokens;                    { Type of Token (Token) is }
  39.     ProgStmts : StmtPtr;                { Pointer To Stored Program }
  40.     CodeStmts : StmtPtr;                { Pointer To Stored Code }
  41.     SHrs,SMin,SSec,SHnd : Word;            { Start Times }
  42.     LineCnt : Word;                        { Lines Processed }
  43.  
  44. FUNCTION UpperStr(StrArg : STRING) : STRING;
  45.  
  46.     VAR
  47.         i : Word;
  48.  
  49.     BEGIN
  50.         FOR  i := 1 TO Length(StrArg) DO
  51.             StrArg[i] := UpCase(StrArg[i]);
  52.         UpperStr := StrArg;
  53.     END;
  54.  
  55. FUNCTION TokenMatch (VAR Token : STRING; VAR ArrArg;
  56.                      ArrSize, Shortest, Longest : Word) : Boolean;
  57.     TYPE
  58.         ArgTyp = ARRAY [1..150] OF SmallStr;
  59.  
  60.     VAR
  61.         i, j : Word;
  62.         TokenLn : Word;
  63.         TokStr : STRING;
  64.         Ch : Char;
  65.  
  66.     BEGIN
  67.         TokenLn := Length(Token);
  68.         TokStr := UpperStr(Token);
  69.         TokenMatch := False;
  70.         i := 1;
  71.  
  72.         IF (TokenLn >= Shortest) AND (TokenLn <= Longest) THEN
  73.             REPEAT
  74.                 Ch := SmallStr(ArgTyp(ArrArg)[i])[1];
  75.                 Ch := UpCase(Ch);
  76.                 IF (TokStr[1] = Ch) THEN
  77.                     IF ( Length(ArgTyp(ArrArg)[i]) = TokenLn ) AND
  78.                        ( TokStr = UpperStr(ArgTyp(ArrArg)[i]) ) THEN
  79.                         BEGIN
  80.                             Token := ArgTyp(ArrArg)[i];
  81.                             TokenMatch := True;
  82.                             Exit;
  83.                         END;
  84.                 Inc(i);
  85.             UNTIL (i > ArrSize) OR (Ch > TokStr[1]);
  86.     END;
  87.  
  88. FUNCTION IsKeyWord(VAR Token : STRING) : Boolean;
  89.  
  90.     CONST
  91.         KeyWordCnt = 52;                    { Number Of KeyWords }
  92.         Shortest = 2;                        { Shortest KeyWord Length }
  93.         Longest = 14;                        { Longest Keyword Length }
  94.  
  95.     TYPE
  96.         KeyWordArray = ARRAY [1..KeyWordCnt] OF SmallStr;
  97.  
  98.     CONST
  99.         KeyWords : KeyWordArray = (
  100.         'ABSOLUTE',    'AND',        'ARRAY',    'BEGIN',    'CASE',
  101.         'CONST',    'CSTRING',    'DIV',        'DO',        'DOWNTO',
  102.         'ELSE',        'END',        'EXTERNAL',    'FILE',        'FOR',
  103.         'FORWARD',    'FUNCTION',    'GOTO',        'IF',        'IMPLEMENTATION',
  104.         'IN',        'INHERITED','INLINE',    'INTERFACE','INTERRUPT',
  105.         'LABEL',    'MOD',        'NIL',        'NOT',        'OBJECT',
  106.         'OF',        'OR',        'OVERRIDE',    'PACKED',    'PROCEDURE',
  107.         'PROGRAM',    'RECORD',    'REPEAT',    'SET',        'SHL',
  108.         'SHR',        'STRING',    'THEN',        'TO',        'TYPE',
  109.         'UNIT',        'UNTIL',    'USES',        'VAR',        'WHILE',
  110.         'WITH',        'XOR' );
  111.  
  112.     BEGIN
  113.         IsKeyWord :=
  114.             TokenMatch(Token, KeyWords, KeyWordCnt, Shortest, Longest);
  115.     END;
  116.  
  117. FUNCTION IsDataType (VAR Token : STRING) : Boolean;
  118.  
  119.     CONST
  120.         DataTypeCnt = 24;                    { Number Of DataTypes }
  121.         Shortest = 4;                        { Shortest DataType Length }
  122.         Longest = 9;                        { Longest DataType Length }
  123.  
  124.     TYPE
  125.         DataTypeArray = ARRAY [1..DataTypeCnt] OF SmallStr;
  126.  
  127.     CONST
  128.         DataTypes : DataTypeArray = (
  129.         'Boolean',    'Byte',        'Char',        'Comp',        'ComStr',
  130.         'DateTime',    'DirStr',    'Double',    'Extended',    'ExtStr',
  131.         'FileRec',    'Integer',    'LongInt',    'NameStr',    'PathStr',
  132.         'Pointer',    'Real',        'Registers','SearchRec','Single',
  133.         'Text',        'TextBuf',    'TextRec',    'Word');
  134.  
  135.     BEGIN
  136.         IsDataType :=
  137.             TokenMatch(Token, DataTypes, DataTypeCnt, Shortest, Longest);
  138.     END;
  139.  
  140. FUNCTION IsConst (VAR Token : STRING) : Boolean;
  141.  
  142.     CONST
  143.         ConstCnt = 57;                        { Number Of Constants }
  144.         Shortest = 3;
  145.         Longest = 12;
  146.  
  147.     TYPE
  148.         ConstArray = ARRAY[1..ConstCnt] OF SmallStr;
  149.  
  150.     CONST
  151.         Constants : ConstArray = (
  152.         'AnyFile',    'Archive',    'Black',    'Blink',    'Blue',
  153.         'Brown',    'BW40',        'BW80',        'C40',        'C80',
  154.         'CO40',        'CO80',        'Cyan',        'DarkGray',    'Directory',
  155.         'ErrorAddr','ExitCode',    'ExitProc',    'False',    'FAuxiliary',
  156.         'FCarry',    'FileMode',    'FMClosed',    'FMInOut',    'FMInput',
  157.         'FMOutput',    'Font8x8',    'FOverflow','FParity',    'FreeMin',
  158.         'FreePtr',    'FSign',    'FZero',    'Green',    'HeapError',
  159.         'HeapOrg',    'HeapPtr',    'Hidden',    'InOutRes',    'LightBlue',
  160.         'LightCyan','LightGray','LightGreen','LightMagenta','LightRed',
  161.         'Magenta',    'Mono',        'PrefixSeg','RandSeed',    'ReadOnly',
  162.         'Red',        'StackLimit','SysFile',    'True',        'VolumeID',
  163.         'White',    'Yellow');
  164.  
  165.     BEGIN
  166.         IsConst :=
  167.             TokenMatch(Token, Constants, ConstCnt, Shortest, Longest);
  168.     END;
  169.  
  170. FUNCTION IsFuncProc (VAR Token : STRING) : Boolean;
  171.  
  172.     CONST
  173.         FuncProcCnt = 142;                    { Number Of Functions }
  174.         Shortest = 2;
  175.         Longest = 14;
  176.  
  177.     TYPE
  178.         FuncProcArray = ARRAY [1..FuncProcCnt] OF SmallStr;
  179.  
  180.     CONST
  181.         FuncProcs : FuncProcArray = (
  182.         'Abs',        'Addr',        'Append',    'ArcTan',    'Assign',
  183.         'AssignCrt','BlockRead','BlockWrite','ChDir',    'Chr',
  184.         'Close',    'ClrEol',    'ClrScr',    'Concat',    'Copy',
  185.         'Cos',        'CSeg',        'Dec',        'Delay',    'Delete',
  186.         'DelLine',    'DiskFree',    'DiskSize',    'Dispose',    'DosExitCode',
  187.         'DosVersion','DSeg',    'EnvCount',    'EnvStr',    'Eof',
  188.         'Eoln',        'Erase',    'Exec',        'Exit',        'Exp',
  189.         'FExpand',    'FilePos',    'FileSize',    'FillChar',    'FindFirst',
  190.         'FindNext',    'First',    'Flush',    'Frac',        'FreeMem',
  191.         'FSearch',    'FSplit',    'GetCBreak','GetDate',    'GetDir',
  192.         'GetEnv',    'GetFAttr',    'GetFTime',    'GetIntVec','GetMem',
  193.         'GetTime',    'GetVerify','GotoXY',    'Halt',        'Hi',
  194.         'HighVideo','Inc',        'Insert',    'InsLine',    'Int',
  195.         'Intr',        'IOResult',    'Keep',        'KeyPressed','Last',
  196.         'Length',    'Ln',        'Lo',        'LowVideo',    'Mark',
  197.         'MaxAvail',    'MemAvail',    'Member',    'MkDir',    'Move',
  198.         'MsDos',    'New',        'NormVideo','NoSound',    'Odd',
  199.         'Ofs',        'Ord',        'PackTime',    'ParamCount','ParamStr',
  200.         'Pi',        'Pos',        'Pred',        'Ptr',        'Random',
  201.         'Randomize','Read',        'ReadKey',    'Readln',    'Release',
  202.         'Rename',    'Reset',    'Rewrite',    'RmDir',    'Round',
  203.         'RunError',    'Seek',        'SeekEof',    'SeekEoln',    'Seg',
  204.         'SetCBreak','SetDate',    'SetFAttr',    'SetFTime',    'SetIntVec',
  205.         'SetTextBuf','SetTime',    'SetVerify','Sin',        'SizeOf',
  206.         'Sound',    'SPtr',        'Sqr',        'Sqrt',        'SSeg',
  207.         'Str',        'Succ',        'Swap',        'SwapVectors','TextBackground',
  208.         'TextColor','TextMode',    'Trunc',    'Truncate',    'UnpackTime',
  209.         'UpCase',    'Val',        'WhereX',    'WhereY',    'Window',
  210.         'Write',    'Writeln');
  211.  
  212.     BEGIN
  213.         IsFuncProc :=
  214.             TokenMatch(Token, FuncProcs, FuncProcCnt, Shortest, Longest);
  215.     END;
  216.  
  217. FUNCTION IsVar (VAR Token : STRING) : Boolean;
  218.  
  219.     CONST
  220.         VarCnt = 35;                        { Number Of Variables }
  221.         Shortest = 3;
  222.         Longest = 11;
  223.  
  224.     TYPE
  225.         VarsArray = ARRAY[1..VarCnt] OF SmallStr;
  226.  
  227.     CONST
  228.         Vars : VarsArray = (
  229.         'CheckBreak','CheckEOF','CheckSnow','DirectVideo','DosError',
  230.         'Input',    'LastMode',    'Lst',        'Mem',        'MemL',
  231.         'MemW',        'Output',    'Port',        'PortW',    'SaveInt00',
  232.         'SaveInt02','SaveInt1B','SaveInt23','SaveInt24','SaveInt34',
  233.         'SaveInt35','SaveInt36','SaveInt37','SaveInt38','SaveInt39',
  234.         'SaveInt3A','SaveInt3B','SaveInt3C','SaveInt3D','SaveInt3E',
  235.         'SaveInt3F','SaveInt75','TextAttr',    'WindMax',    'WindMin');
  236.  
  237.     BEGIN
  238.         IsVar :=
  239.             TokenMatch(Token, Vars, VarCnt, Shortest, Longest);
  240.     END;
  241.  
  242. FUNCTION IsCode(VAR Token : STRING) : Boolean;
  243.  
  244.     VAR
  245.         CodeTbl : StmtPtr;
  246.         LastTbl : StmtPtr;
  247.         TokStr : STRING;
  248.         TokLen : Word;
  249.         LPtrSize : LongInt;
  250.  
  251.     BEGIN
  252.         TokStr := UpperStr(Token);
  253.         TokLen := Length(Token);
  254.         CodeTbl := CodeStmts;
  255.         LastTbl := CodeStmts;
  256.  
  257.         WHILE (CodeTbl <> NIL) DO
  258.             BEGIN
  259.                 IF (TokLen = Length(CodeTbl^.Stmt)) AND
  260.                    (TokStr = UpperStr(CodeTbl^.Stmt)) THEN
  261.                         BEGIN
  262.                             Token := CodeTbl^.Stmt;
  263.                             IsCode := True;
  264.                             Exit;
  265.                         END
  266.                 ELSE
  267.                     BEGIN
  268.                         LastTbl := CodeTbl;
  269.                         CodeTbl := CodeTbl^.Next;
  270.                     END;
  271.             END;
  272.  
  273.         IF (CodeStmts = NIL) THEN
  274.             BEGIN
  275.                 Mark(CodeStmts);
  276.                 LastTbl := CodeStmts;
  277.             END;
  278.  
  279.         TokLen := SizeOf(StmtPtr) + Length(Token) + 1;
  280.         LPtrSize := TokLen;
  281.         GetMem(CodeTbl, TokLen);
  282.         LastTbl^.Next := CodeTbl;
  283.         CodeTbl^.Stmt := Token;
  284.         CodeTbl^.Next := NIL;
  285.         IsCode := False;
  286.     END;
  287.  
  288. FUNCTION IsComment(VAR Flag : Boolean;
  289.                    VAR NeedToken : STRING;
  290.                    VAR Token : STRING) : Boolean;
  291.  
  292.     BEGIN
  293.         IF Flag AND (TokenType = Other) THEN
  294.             IF (Pos(NeedToken, Token) <> 0) THEN
  295.                 BEGIN
  296.                     Flag := False;
  297.                     NeedToken := '';
  298.                 END
  299.             ELSE
  300.                 Flag := True
  301.         ELSE
  302.             IF (Pos('{', Token) <> 0) THEN
  303.                 BEGIN
  304.                     Flag := True;
  305.                     NeedToken := '}';
  306.                 END
  307.             ELSE
  308.                 IF (Pos('(*', Token) <> 0) THEN
  309.                     BEGIN
  310.                         Flag := True;
  311.                         NeedToken := '*)'
  312.                     END;
  313.  
  314.         IsComment := Flag;
  315.     END;
  316.  
  317. FUNCTION HaveCmdParams : Boolean;
  318.  
  319.     VAR
  320.         i : Integer;
  321.         TmpStr : STRING;
  322.  
  323.     PROCEDURE AddExtension;
  324.  
  325.         BEGIN
  326.             IF (Pos('.', TmpStr) = 0) THEN
  327.                 TmpStr := Concat(TmpStr, '.PAS');
  328.         END;
  329.  
  330.     BEGIN
  331.         IF (ParamCount < 1) OR (ParamCount > 2) THEN
  332.             BEGIN
  333.                 Writeln('Usage: QPF InFileName [OutFileName]');
  334.                 HaveCmdParams := False;
  335.             END
  336.         ELSE
  337.             BEGIN
  338.                 TmpStr := ParamStr(1);
  339.                 AddExtension;
  340.                 InFileName := UpperStr(TmpStr);
  341.  
  342.                 IF (ParamCount = 2) THEN
  343.                     BEGIN
  344.                         TmpStr := ParamStr(2);
  345.                         AddExtension;
  346.                         OutFileName := UpperStr(TmpStr);
  347.                     END
  348.                 ELSE
  349.                     OutFileName := InFileName;
  350.                 HaveCmdParams := True;
  351.             END;
  352.     END;
  353.  
  354. FUNCTION LoadedOK : Boolean;
  355.  
  356.     VAR
  357.         InFile : Text;
  358.         InStmt : STRING;
  359.         LastStmt : StmtPtr;
  360.  
  361.     FUNCTION OpenOk : Boolean;
  362.  
  363.         VAR
  364.             Status : Word;
  365.  
  366.         BEGIN
  367.             Assign(InFile, InFileName);
  368.             Reset(InFile);
  369.             Status := IOResult;
  370.             IF (Status = 0) THEN
  371.                 OpenOk := True
  372.             ELSE
  373.                 BEGIN
  374.                     Writeln('Error ',Status,' Opening ', InFileName);
  375.                     OpenOk := False
  376.                 END;
  377.         END;
  378.  
  379.     PROCEDURE StoreStmt;
  380.  
  381.         VAR
  382.             PtrSize : Word;
  383.             NewStmt : StmtPtr;
  384.  
  385.         BEGIN
  386.             PtrSize := SizeOf(StmtPtr) + Length(InStmt) + 1;
  387.             IF (ProgStmts = NIL) THEN
  388.                 Mark(ProgStmts);
  389.             GetMem(NewStmt, PtrSize);
  390.             IF (LastStmt = NIL) THEN
  391.                 LastStmt := ProgStmts
  392.             ELSE
  393.                 LastStmt^.Next := NewStmt;
  394.             NewStmt^.Stmt := InStmt;
  395.             NewStmt^.Next := NIL;
  396.             LastStmt := NewStmt;
  397.         END;
  398.  
  399.     BEGIN
  400.         LastStmt := NIL;                    { Init Statement Array }
  401.         IF NOT OpenOk THEN
  402.             LoadedOK := False
  403.         ELSE
  404.             BEGIN
  405.                 WHILE NOT Eof(InFile) DO
  406.                     BEGIN
  407.                         Readln(InFile, InStmt);
  408.                         StoreStmt;
  409.                     END;
  410.                 LoadedOK := True;
  411.                 Close(InFile);
  412.             END;
  413.     END;
  414.  
  415. PROCEDURE GetToken(VAR Stmt : STRING;  VAR StartPos, EndPos : Word);
  416.  
  417.     CONST
  418.         SpaceChrs : SET OF Char = [' ',#9];
  419.  
  420.     VAR
  421.         StmtLen,CurPos : Word;
  422.         Ch : Char;
  423.         Flg : Boolean;
  424.  
  425.     PROCEDURE Build_Ident;
  426.  
  427.         BEGIN
  428.             StartPos := CurPos;
  429.             TokenType := Identifier;
  430.             WHILE (CurPos <= StmtLen) AND
  431.                   (Stmt[CurPos] IN (IdentSet + DigitSet)) DO
  432.                 BEGIN
  433.                     Token := Token + Stmt[CurPos];
  434.                     EndPos := CurPos;
  435.                     Inc(CurPos);
  436.                 END;
  437.         END;
  438.  
  439.     PROCEDURE Build_Token;
  440.  
  441.         BEGIN
  442.             StartPos := CurPos;
  443.             TokenType := Other;
  444.             WHILE (CurPos <= StmtLen) AND (Stmt[CurPos] IN DelimSet) DO
  445.                 BEGIN
  446.                     Token := Token + Stmt[CurPos];
  447.                     EndPos := CurPos;
  448.                     Inc(CurPos);
  449.                 END;
  450.         END;
  451.  
  452.     PROCEDURE Build_Literal;
  453.  
  454.     TYPE
  455.         Literals = (Quoted, Hex, Decimal, Float);
  456.         Char_Set = SET OF Char;
  457.  
  458.     VAR
  459.         Literal_Type : Literals;
  460.         CurSet : Char_Set;
  461.  
  462.         BEGIN
  463.             StartPos := CurPos;
  464.             TokenType := Literal;
  465.             CASE Stmt[CurPos] OF
  466.                 '0'..'9':
  467.                     BEGIN
  468.                         Literal_Type := Float;
  469.                         CurSet := DigitSet + ['.'];
  470.                     END;
  471.                 '''':
  472.                     BEGIN
  473.                         Literal_Type := Quoted;
  474.                         CurSet := [#0..#255];
  475.                     END;
  476.                 '$':
  477.                     BEGIN
  478.                         Literal_Type := Hex;
  479.                         CurSet := HexSet;
  480.                     END;
  481.                 '#':
  482.                     BEGIN
  483.                         Literal_Type := Decimal;
  484.                         CurSet := DigitSet;
  485.                     END
  486.                 ELSE
  487.                     Writeln('Unknown Token Type');
  488.             END;
  489.  
  490.             Token := Token + Stmt[CurPos];
  491.             EndPos := CurPos;
  492.             Inc(CurPos);
  493.  
  494.             WHILE (CurPos <= StmtLen) AND
  495.                   (Stmt[CurPos] IN CurSet) DO
  496.                 BEGIN
  497.                     Token := Token + Stmt[CurPos];
  498.                     EndPos := CurPos;
  499.                     Inc(CurPos);
  500.                     IF (Literal_Type = Quoted) AND
  501.                        (Stmt[CurPos-1] = Quote) THEN
  502.                         Exit;
  503.                 END;
  504.         END;
  505.  
  506.     BEGIN
  507.         StmtLen := Length(Stmt);
  508.         Token := '';
  509.         CurPos := StartPos;
  510.  
  511.         WHILE (CurPos <= StmtLen) AND (Stmt[CurPos] IN SpaceChrs) DO
  512.             Inc(CurPos);
  513.  
  514.         WHILE (CurPos <= StmtLen) DO
  515.             BEGIN
  516.                 Ch := Stmt[CurPos];
  517.                 IF (Ch IN IdentSet) THEN
  518.                     BEGIN
  519.                         Build_Ident;
  520.                         Exit;
  521.                     END;
  522.  
  523.                 IF (Ch IN DelimSet) THEN
  524.                     BEGIN
  525.                         Build_Token;
  526.                         Exit;
  527.                     END;
  528.  
  529.                 IF (Ch IN DigitSet) OR (Ch IN LiteralSet) THEN
  530.                     BEGIN
  531.                         Build_Literal;
  532.                         Exit;
  533.                     END;
  534.  
  535.                 Inc(CurPos);
  536.             END;
  537.     END;
  538.  
  539. PROCEDURE FormatIn;
  540.  
  541.     VAR
  542.         SkipFlg : Boolean;
  543.         SkipToken : STRING;
  544.         CurStmt : StmtPtr;
  545.         TStart, TEnd : Word;
  546.  
  547.     PROCEDURE AnalyzeToken;
  548.  
  549.         BEGIN
  550.             IF (SkipFlg) AND IsComment(SkipFlg, SkipToken, Token) THEN
  551.                 Exit;
  552.  
  553.             CASE TokenType OF
  554.                 Identifier :
  555.                     BEGIN
  556.                         IF IsKeyWord(Token) OR
  557.                            IsFuncProc(Token) OR
  558.                            IsDataType(Token) OR
  559.                            IsVar(Token) OR
  560.                            IsConst(Token) OR
  561.                            IsCode(Token) THEN
  562.                             Move(Token[1],
  563.                                  CurStmt^.Stmt[TStart],
  564.                                  Length(Token));
  565.                     END;
  566.                 Other:
  567.                     IF IsComment(SkipFlg, SkipToken, Token) THEN
  568.                         Exit;
  569.                 Literal:
  570.                     Exit;
  571.             END;
  572.         END;
  573.  
  574.     BEGIN    { Procedure FormatIn }
  575.         CurStmt := ProgStmts;
  576.         SkipFlg := False;
  577.         SkipToken := '';
  578.         LineCnt := 0;
  579.         Write(InFileName, '(');
  580.         WHILE(CurStmt <> NIL) DO
  581.             BEGIN
  582.                 TStart := 1;
  583.                 TEnd := 1;
  584.                 Inc(LineCnt);
  585.                 WHILE (TStart <= Length(CurStmt^.Stmt)) DO
  586.                     BEGIN
  587.                         GetToken(CurStmt^.Stmt, TStart, TEnd);
  588.                         AnalyzeToken;
  589.                         TStart := TEnd + 1;
  590.                     END;
  591.                 CurStmt := CurStmt^.Next;
  592.                 IF (LineCnt MOD 10 = 0) THEN
  593.                     BEGIN
  594.                         Write(LineCnt,')',Chr(8));
  595.                         TStart := LineCnt;
  596.                         REPEAT
  597.                             Write(Chr(8));
  598.                             TStart := TStart DIV 10;
  599.                         UNTIL (TStart = 0);
  600.                     END;
  601.             END;
  602.     END;
  603.  
  604. PROCEDURE FormatOut;
  605.  
  606.     VAR
  607.         OutFile : Text;
  608.         CurStmt : StmtPtr;
  609.  
  610.     BEGIN
  611.         CurStmt := ProgStmts;
  612.         Assign(OutFile, OutFileName);
  613.         Rewrite(OutFile);
  614.         LineCnt := 0;
  615.         WHILE (CurStmt <> NIL) DO
  616.             BEGIN
  617.                 Writeln(OutFile, CurStmt^.Stmt);
  618.                 CurStmt := CurStmt^.Next;
  619.                 Inc(LineCnt);
  620.             END;
  621.         Release(ProgStmts);
  622.         Close(OutFile);
  623.     END;
  624.  
  625. PROCEDURE ShowStats;
  626.  
  627.     TYPE
  628.         STR2 = STRING[2];
  629.  
  630.     FUNCTION NumStr2(Num : Word) : STR2;
  631.  
  632.         VAR
  633.             NumStr : STRING;
  634.  
  635.         BEGIN
  636.             Str(Num+100:3, NumStr);
  637.             NumStr2 := Copy(NumStr, 2, 2);
  638.         END;
  639.  
  640.     VAR
  641.         STime,Etime : LongInt;
  642.         EHrs,EMin,ESec,EHnd : Word;            { End Times }
  643.         TimeStr : STRING;
  644.  
  645.     BEGIN
  646.         GetTime(EHrs, EMin, ESec, EHnd);
  647.         STime := (SMin * 60 + SSec) * 100 + SHnd;
  648.         STime := STime + LongInt (SHrs) * 36000;
  649.         Etime := (EMin * 60 + ESec) * 100 + EHnd;
  650.         Etime := Etime + LongInt (EHrs) * 36000;
  651.         Etime := Etime - STime;
  652.         EHnd := Etime MOD 100;
  653.         Etime := Etime DIV 100;
  654.         EHrs := Etime DIV 3600;
  655.         Etime := Etime MOD 3600;
  656.         EMin := Etime DIV 60;
  657.         ESec := Etime MOD 60;
  658.         TimeStr := NumStr2(EHrs) + ':' +
  659.                    NumStr2(EMin) + ':' +
  660.                    NumStr2(ESec) + '.' + NumStr2(EHnd);
  661.         Writeln;
  662.         Writeln('Lines: ',LineCnt);
  663.         Writeln('Elapsed Time = ',TimeStr);
  664.     END;
  665.  
  666. BEGIN    { Program Start }
  667.     CodeStmts := NIL;
  668.     ProgStmts := NIL;
  669.  
  670.     Writeln('MAT Enterprises, Quick Pascal Word Fixup  V1.0');
  671.     Writeln;
  672.     IF HaveCmdParams THEN
  673.         BEGIN
  674.             GetTime(SHrs, SMin, SSec, SHnd);
  675.             IF LoadedOK THEN
  676.                 BEGIN
  677.                     FormatIn;
  678.                     FormatOut;
  679.                     ShowStats
  680.                 END;
  681.         END;
  682. END.
  683.